﻿<!DOCTYPE html>
<html>
    <!--
        Copyright (C) 2013-2014 Ralph Becket 
        Released under a variant of the Microsoft Public License -- see ../LICENCE.txt.
        A demonstration of the Rawb controls.
    -->
    <head>
        <title>RawbGrid</title>
        <link rel="stylesheet" href="css/rawb.css" />
    </head>

    <body>

        <h1>Rawb Controls Demo</h1>

        <div style="float: left; border-left: 1px solid black; padding: 0 1em 0 1em">

            <h3>Grid</h3>

            Things to try:
            <ul>
                <li>clicking on a row;</li>
                <li>clicking on a row header;</li>
                <li>ticking a row checkbox;</li>
                <li>resizing a column;</li>
                <li>moving the scrollbars;</li>
                <li>using the mouse-wheel;</li>
                <li>focussing on the grid and using the up/down/page up/page down/home/end keys;</li>
                <li>resizing the grid via the resizing corner.</li>
            </ul>

            <div data-bind="template: { name: 'RawbGridTemplate', data: myGrid }"></div>

            <p data-bind="
                text: (myGrid.selection() ? 'Row ' + myGrid.selection().i : 'No row') + ' selected.'
            "></p>

        </div>

        <div style="float: left; border-left: 1px solid black; padding: 0 1em 0 1em">

            <h3>DropDown</h3>

            Things to try:
            <ul>
                <li>focussing on/off the drop-down input box;</li>
                <li>typing some characters into the input box;</li>
                <li>scrolling the selection in the drop-down list with the scroll-bar, mouse-wheel, or arrow keys;</li>
                <li>hitting Enter or Tab when a drop-down row is selected/not selected;</li>
                <li>hitting Enter or Tab when the drop-down list has only one item.</li>
            </ul>

            <div data-bind="template: { name: 'RawbDropDownTemplate', data: myDropDown }"></div>

        </div>

        <div style="float: left; border-left: 1px solid black; padding: 0 1em 0 1em">

            <h3>ManagedInput</h3>

            Things to try:
            <ul>
                <li>focussing on/off the input box;</li>
                <li>editing the input box contents -- type in various numbers.</li>
            </ul>

            <div data-bind="template: { name: 'RawbManagedInputTemplate', data: myManagedInput }"></div>

        </div>

        <script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-3.0.0.debug.js"></script>
        <!--<script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-3.0.0.js"></script>-->
        <script src="js/rawb.loader.js"></script>
        <script src="js/rawb.util.js"></script>
        <script src="js/rawb.ui.js"></script>
        <!-- html/rawb.ui.html -->

<!-- Copyright (C) 2013-2014 Ralph Becket -->
<!-- Released under a variant of the Microsoft Public License -- see ../LICENCE.txt. -->


<!-- (Public template) RawbAreaResizingHandleTemplate -->
<!-- Adds a resizing "handle" to the lower right of its container, -->
<!-- which must support absolutely positioned children. -->
<!-- PARAMETERS -->
<!--
    hAndVDragger: the dragger controlling the resizing.
-->
<script type="text/html" id="RawbAreaResizingHandleTemplate">
    <div
        class="rawb-area-resizing-handle"
        data-bind="event: { mousedown: startDragging }"
    >
    </div>
</script>

<!-- (Private template) RawbGridRowOfHeaderCellsTemplate -->
<!-- PARAMETERS -->
<!-- columns: array of column specs. -->
<!--    Each column spec defines left, width, headerTemplateID, headerFormatter, and header. -->
<!-- headerRowHeight: height in pixels of cells in the row. -->
<script type="text/html" id="RawbGridRowOfHeaderCellsTemplate">

    <!-- ko foreach: columns -->

        <div
            class="rawb-grid-cell"
            data-bind="
    style: {
        left: left() + 'px',
        width: width() + 'px',
        height: $parent.headerRowHeight() + 'px'
    },
    template: {
        if: header !== undefined,
        name: headerTemplateID,
        data: { data: function () { return header; }, formatter: headerFormatter }
    },
    event: {
        click: headerClick,
        dblclick: headerDblClick
    }"
        >
        </div>

        <div
            class="rawb-grid-resizer"
            data-bind="
    style: {
        left: left() + width() + 'px',
        width: $parent.resizerWidth() + 'px',
        height: $parent.headerRowHeight() + 'px'
    },
    event: {
        mousedown: resizer.startDragging
    }"
        >
        </div>

    <!-- /ko -->

</script>

<!-- (Private template) RawbGridRowsOfValueCellsTemplate -->
<!-- PARAMETERS -->
<!-- columns: array of column specs. -->
<!--    Each column spec defines left, width, valueTemplateID, valueFormatter, and valueField. -->
<!-- valueRowHeight: height in pixels of cells in each row. -->
<!-- rows: array of value objects to display. -->
<!-- -->
<!-- Each grid cell template has the following data context: -->
<!--    data: the cell data; -->
<!--    formatter: the cell formatter; -->
<!--    row: the source row from which this cell data is drawn; -->
<!--    gridParent: the value bound to the context containing the grid. -->
<!-- -->
<!-- The identity function around the template data argument prevents -->
<!-- Knockout from placing a dependency on the cell. -->
<!-- This is very important for performance: without it, Knockout will -->
<!-- re-render on every grid scroll event! -->
<script type="text/html" id="RawbGridRowsOfValueCellsTemplate">

    <!-- ko foreach: { data: rows, as: "r" } -->

        <!-- ko foreach: { data: $parent.columns, as: "c" } -->

            <div
                class="rawb-grid-cell"
                data-bind="
                    style: {
                        left: c.left() + 'px',
                        width: c.width() + 'px',
                        top: $parentContext.$index() * $parents[1].valueRowHeight() + 'px',
                        height: $parents[1].valueRowHeight() + 'px'
                    },
                    css: {
                         'rawb-grid-striped': ($parentContext.$index() + $parents[1].topRowIndex()) % (2 * $parents[1].rowsPerStripe()) < $parents[1].rowsPerStripe(),
                         'rawb-grid-selected': ($parents[1].selection() && $parents[1].selection() === $parents[1].data()[$parents[1].topRowIndex() + $parentContext.$index()])
                    },
                    template: {
                        if: r.__rawbRowSrc,
                        name: valueTemplateID,
                        data: {
                            data: r[c.valueField],
                            formatter: c.valueFormatter,
                            row: r.__rawbRowSrc,
                            gridParent: $parents[4]
                        }
                    },
                    event: {
                        click: function () { $parents[1].valueRowClick($parents[1].data()[$parents[1].topRowIndex() + $parentContext.$index()]); return true; },
                        dblclick: function () { $parents[1].valueRowDblClick($parents[1].data()[$parents[1].topRowIndex() + $parentContext.$index()]); return true; }
                    }"
            >
            </div>

            <div
                class="rawb-grid-resizer"
                data-bind="
    style: {
        left: c.left() + c.width() + 'px',
        width: $parents[1].resizerWidth() + 'px',
        top: $parentContext.$index() * $parents[1].valueRowHeight() + 'px',
        height: $parents[1].valueRowHeight() + 'px'
    },
    event: {
        mousedown: c.resizer.startDragging
    }"
            >
            </div>

        <!-- /ko -->

    <!-- /ko -->

</script>

<!-- (Private template) RawbGridRowOfFooterCellsTemplate -->
<!-- PARAMETERS -->
<!-- columns: array of column specs. -->
<!--    Each column spec defines left, width, footerTemplateID, footerFormatter, and footer. -->
<!-- footerRowHeight: height in pixels of cells in the row. -->
<script type="text/html" id="RawbGridRowOfFooterCellsTemplate">

    <!-- ko foreach: columns -->

        <div
            class="rawb-grid-cell"
            data-bind="
    style: {
        left: left() + 'px',
        width: width() + 'px',
        height: $parent.footerRowHeight() + 'px'
    },
    template: {
        if: footer !== undefined,
        name: footerTemplateID,
        data: { data: function () { return footer; }, formatter: footerFormatter }
    },
    event: {
        click: footerClick,
        dblclick: footerDblClick
    }"
        >
        </div>

        <div
            class="rawb-grid-resizer"
            data-bind="
    style: {
        left: left() + width() + 'px',
        width: $parent.resizerWidth() + 'px',
        height: $parent.footerRowHeight() + 'px'
    },
    event: {
        mousedown: resizer.startDragging
    }"
        >
        </div>

    <!-- /ko -->

</script>

<!-- (Private template) RawbGridHeaderValuesFooterTemplate -->
<!-- PARAMETERS -->
<!-- left, headerTop, valuesTop, footerTop: absolute positions in pixels. -->
<!-- width, resizerWidth, headerRowHeight, footerRowHeight, valueRowHeight, valuesHeight: dimensions in pixels. -->
<!-- columns: array of column specs. -->
<!--    Each column spec defines left, width, -->
<!--    header, headerFormatter, headerTemplateID, -->
<!--    footer, footerFormatter, footerTemplateID, -->
<!--    valueField, valueFormatter, valueTemplateID. -->
<!-- rows: array of value objects to display. -->
<script type="text/html" id="RawbGridHeaderValuesFooterTemplate">

    <div
        class="rawb-grid-header rawb-grid-section"
        data-bind="
    style: {
        left: left() + 'px',
        width: width() + 'px',
        top: headerTop() + 'px',
        height: headerRowHeight() + 'px'
    },
    css: sideCssClass,
    template: {
        name: 'RawbGridRowOfHeaderCellsTemplate',
        data: headerViewModel
    }
    ">
    </div>

    <div
        class="rawb-grid-values rawb-grid-section"
        data-bind="
    style: {
        left: left() + 'px',
        width: width() + 'px',
        top: valuesTop() + 'px',
        height: valuesHeight() + 'px'
    },
    css: sideCssClass,
    template: {
        name: 'RawbGridRowsOfValueCellsTemplate',
        data: valuesViewModel
    }
    ">
    </div>

    <div
        class="rawb-grid-footer rawb-grid-section"
        data-bind="
    style: {
        left: left() + 'px',
        width: width() + 'px',
        top: footerTop() + 'px',
        height: footerRowHeight() + 'px'
    },
    css: sideCssClass,
    template: {
        name: 'RawbGridRowOfFooterCellsTemplate',
        data: footerViewModel
    }
    ">
    </div>

</script>

<!-- (Public template) RawbVScrollBarTemplate -->
<!-- PARAMETERS -->
<!-- left, width, top, height: absolute position in pixels. -->
<!-- scrollBar: the Rawb ScrollBar object. -->
<script type="text/html" id="RawbVScrollBarTemplate">

    <div
        class="rawb-scrollbar-track rawb-scrollbar-vertical"
        data-bind="
    style: {
        left: left() + 'px',
        width: width() + 'px',
        top: top() + 'px',
        height: height() + 'px'
    }
        ">

        <div
            class="rawb-scrollbar-thumb"
            data-bind="
    style: {
        left: 0,
        width: width() + 'px',
        top: scrollBar.startPc() + '%',
        height: scrollBar.thumbSize() + '%'
    },
    event: {
        mousedown: scrollBar.startDragging
    }
            ">
        </div>

    </div>

</script>

<!-- (Public template) RawbHScrollBarTemplate -->
<!-- PARAMETERS -->
<!-- left, width, top, height: absolute position in pixels. -->
<!-- scrollBar: the Rawb ScrollBar object. -->
<script type="text/html" id="RawbHScrollBarTemplate">

    <div
        class="rawb-scrollbar-track rawb-scrollbar-horizontal"
        data-bind="
    style: {
        left: left() + 'px',
        width: width() + 'px',
        top: top() + 'px',
        height: height() + 'px'
    }
        ">

        <div
            class="rawb-scrollbar-thumb"
            data-bind="
    style: {
        left: scrollBar.startPc() + '%',
        width: scrollBar.sizePc() + '%',
        top: 0,
        height: height() + 'px'
    },
    event: {
        mousedown: scrollBar.startDragging
    }
            ">
        </div>

    </div>

</script>

<script id="RawbNativeVScrollBarTemplate" type="text/html">

    <div class="rawb-native-v-scrollbar"
            data-bind="
                style: {
                    height: height() + 'px',
                    width: width() + 'px',
                    top: top() + 'px',
                    left: left() + 'px'
                },
                event: {
                    scroll: onScroll
                },
                visible: width()
        ">

            <div class="rawb-native-v-scrollbar-content"
                data-bind="
                    style: {
                        height: contentHeight() + 'px'
                    }
                ">
            </div>

    </div>

</script>

<!-- (Public template) RawbGridTemplate -->
<!-- All parameters are encapsulated in the Rawb Grid object, the parameter of the template. -->
<script type="text/html" id="RawbGridTemplate">

    <div 
        class="rawb-grid"
        tabindex="0"
        data-bind="
    style: {
        width: width() + 'px',
        height: height() + 'px'
    },
    event: {
        keydown: keyDown,
        mousewheel: mouseWheel
    }
        ">

        <!-- ko
            template: {
                name: 'RawbGridHeaderValuesFooterTemplate',
                data: leftViewModel
            }
        -->
        <!-- /ko -->

        <div class="rawb-grid-middle-container"
             data-bind="
    style: {
        width: middleWidth() + 'px',
        height: height() + 'px',
        top: headerTop() + 'px',
        left: middleLeft() + 'px',
        overflowX: overflowX
    }
            ">
            <!-- ko
                template: {
                    name: 'RawbGridHeaderValuesFooterTemplate',
                    data: middleViewModel
                }
            -->
            <!-- /ko -->
        </div>

        <!-- ko
            template: {
                name: 'RawbNativeVScrollBarTemplate',
                data: nativeVScrollBarViewModel,
                afterRender: nativeVScrollBarViewModel.afterRender
            }
        -->
        <!-- /ko -->

        <!-- ko
            template: {
                name: 'RawbGridHeaderValuesFooterTemplate',
                data: rightViewModel
            }
        -->
        <!-- /ko -->

        <!-- ko
            template: {
                if: includeResizingHandle,
                name: 'RawbAreaResizingHandleTemplate',
                data: resizingDragger
            }
        -->
        <!-- /ko -->

    </div>

</script>

<!-- Basic Rawb Grid cell templates.  RawbGridTextCellTemplate is the default. -->

<script type="text/html" id="RawbGridTextCellTemplate">

    <span data-bind="text: formatter(data())"></span>

</script>

<script type="text/html" id="RawbGridRightAlignedTextCellTemplate">

    <span style="float: right" data-bind="text: formatter(data())"></span>

</script>

<script type="text/html" id="RawbGridCentredTextCellTemplate">

    <span style="display: block; text-align: center" data-bind="text: formatter(data())"></span>

</script>

<script type="text/html" id="RawbGridCenteredTextCellTemplate">

    <span style="display: block; margin-left: auto; margin-right: auto" data-bind="text: formatter(data())"></span>

</script>

<!-- NOTE: It is important to exclude grid cell inputs from the tabbing order.  Try it if you doubt me! -->
<script type="text/html" id="RawbGridCheckboxCellTemplate">

    <input
        type="checkbox"
        tabindex="-1"
        class="rawb-grid-cell-checkbox"
        data-bind="checked: data()"
    >

</script>

<script type="text/html" id="RawbDropDownTemplate">
    <div
        class="rawb-dropdown"
        data-bind="
    style: { width: width() + 'px', height: inputHeight() + 'px' },
    css: { 'rawb-dropdown-grid-is-open': displayingGrid }
        ">
        <input
            class="rawb-dropdown-input"
            data-bind="
    value: input,
    enable: enabled,
    valueUpdate: 'afterkeydown',
    event: {
        focus: inputFocus,
        mouseup: inputMouseUp,
        blur: inputBlur,
        keydown: inputKeyDown,
        keypress: inputKeyPress
    }
            ">
        <div
            class="rawb-dropdown-grid"
            data-bind="
    visible: matches().length,
    event: { mousedown: gridMouseDown, mouseout: gridMouseOut, click: gridClick },
    template: {
        if: displayingGrid,
        name: 'RawbGridTemplate',
        data: grid
    },
    style: { left: gridLeft + 'px', top: '100%' }
        ">
        </div>
    </div>
</script>

<script type="text/html" id="RawbDropDownMatchTemplate">
    <div data-bind="if: data()">
        <span class="rawb-dropdown-match-prefix" data-bind="text: data().prefix"></span><span class="rawb-dropdown-match-match" data-bind="    text: data().match"></span><span class="rawb-dropdown-match-suffix" data-bind="    text: data().suffix"></span>
    </div>
</script>

<script type="text/html" id="RawbManagedInputTemplate">
    <input data-bind="
    value: input,
    enable: enabled,
    event: { focus: inputFocus, blur: inputBlur }
    ">
</script>

        <script>

            // rawb.loadAndAddHtml("html/rawb.ui.html");
            
            rawb.runAfterLoading(function () {

                myData = ko.observableArray([]);

                var n = 1000;

                for (var i = 0; i < n; i++) {
                    var rad = i * 2 * Math.PI / n;
                    myData.push({
                        i: i + 1,
                        rad: rad,
                        sin: Math.sin(rad),
                        cos: Math.cos(rad),
                        tan: Math.tan(rad),
                        log10: Math.log(i + 1) * Math.LOG10E,
                        date: new Date(new Date().valueOf() - (100000000000 * Math.random())),
                        name: ["Alice", "Bob", "Cissy", "Dick", "Emma"][i % 5],
                        checked: ko.observable(false)
                    });
                }

                var plus = function (x, y) { return 0 + ko.unwrap(x) + ko.unwrap(y); };

                sumCol = function (col) {
                    return ko.computed(function () { 
                        return myData().map(function (x) { return x && x[col]; }).reduce(plus);
                    });
                };

                var fix3 = function (x) { x = ko.unwrap(x); return isFinite(x) ? x.toFixed(3) : ""; };

                var asChecked = function (x) {
                    return { checked: x };
                };

                numChecked = sumCol("checked");

                var centred = "RawbGridCentredTextCellTemplate";
                var rightAligned = "RawbGridRightAlignedTextCellTemplate";

                myGrid = new rawb.Grid({
                    width: 450,
                    height: 340,
                    resizerWidth: 2,
                    leftColumns: [
                        {
                            width: 40, header: "Row",
                            //headerClick: function () { alert("Header click!"); },
                            valueField: "i", valueTemplateID: centred,
                            footer: n,
                            footerClick: function () { alert("Footer click!"); }
                        }
                    ],
                    columns: [
                        {
                            width: 60, header: "rad (2pi/" + n + ")",
                            valueField: "rad", valueFormatter: fix3, valueTemplateID: rightAligned
                        },
                        {
                            width: "15%", header: "sin",
                            valueField: "sin", valueFormatter: fix3,
                            footer: sumCol("sin"), footerFormatter: fix3, valueTemplateID: rightAligned
                        },
                        {
                            width: "15%", header: "cos",
                            valueField: "cos", valueFormatter: fix3,
                            footer: sumCol("cos"), footerFormatter: fix3, valueTemplateID: rightAligned
                        },
                        {
                            width: "15%", header: "tan",
                            valueField: "tan", valueFormatter: fix3, valueTemplateID: rightAligned
                        },
                        {
                            width: "15%", header: "log",
                            valueField: "log10", valueFormatter: fix3, valueTemplateID: rightAligned
                        },
                        {
                            width: "20%", header: "Date",
                            valueField: "date"
                        },
                        {
                            width: "20%", header: "Name",
                            valueField: "name"
                        }
                    ],
                    rightColumns: [
                        {
                            width: 40,
                            valueField: "checked", valueFormatter: undefined, valueTemplateID: "RawbGridCheckboxCellTemplate",
                            footer: numChecked, footerTemplateID: centred
                        }
                    ],
                    click: function (row) {
                        myGrid.selection(row);
                    },
                    data: myData,
                    includeResizingHandle: true,
                    rowsPerStripe: 3
                });

                myDropDown = new rawb.DropDown({
                    width: 200,
                    inputHeight: 24,
                    gridHeight: 100,
                    gridRowHeight: 20,
                    options: [
                        { label: "Alice" },
                        { label: "Aaron" },
                        { label: "Bob" },
                        { label: "Belle" },
                        { label: "Cissy" },
                        { label: "Charles" },
                        { label: "Debby" },
                        { label: "Dilbert" },
                        { label: "Edgar" },
                        { label: "Ethel" }
                    ],
                    fieldName: "label",
                    fetchFn: function () { console.log("[fetchFn]"); }
                });

                myManagedInput = new rawb.ManagedInput({
                    displayFormatter: function (value) {
                        if (!isFinite(value)) return "";
                        var s = value.toFixed(2);
                        for (var i = s.indexOf(".") - 3; 0 < i; i -= 3)
                            s = s.substr(0, i) + "," + s.substr(i);
                        return "$ " + s;
                    },
                    editFormatter: function (value) {
                        return (isFinite(value) ? value.toFixed(2) : "");
                    },
                    parser: function (input) {
                        return (input != "" ? +input : undefined);
                    }
                });

                ko.applyBindings({ myGrid: myGrid, myDropDown: myDropDown, myManagedInput: myManagedInput });

            });

        </script>
    </body>
</html>